﻿using System;
using System.Reflection;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;

namespace Entropy.Proxy
{
    class RealProxyBased : RealProxy, IRemotingTypeInfo
    {
        private readonly object origin;
        private readonly RemotingInvocation callback;

        public RealProxyBased(object origin, RemotingInvocation callback)
            : base(typeof(MarshalByRefObject))
        {
            this.origin = origin;
            this.callback = callback;
        }

        public override IMessage Invoke(IMessage msg)
        {
            var call = (IMethodCallMessage)msg;
            return callback(call, InvokeOrigin);
        }

        IMethodReturnMessage InvokeOrigin(IMethodCallMessage call, RemotingInvocation target)
        {
            MethodBase method = call.MethodBase;
            try
            {
                var parameters = call.Args;
                var ret = method.Invoke(origin, parameters);
                return new ReturnMessage(ret, parameters,
                                         call.ArgCount, call.LogicalCallContext, call);
            }
            catch (TargetInvocationException e)
            {
                var innerException = e.InnerException;
                if (innerException != null)
                    throw innerException;
                throw;
            }
        }

        public bool CanCastTo(Type fromType, object o)
        {
            return true;
        }

        public string TypeName
        {
            get { throw new NotSupportedException(); }
            set { throw new NotSupportedException(); }
        }
    }
}